<template>
	<div class="comp-dynamic-table">
		<el-form ref="formInstance" :model="formData" @submit.prevent>
			<table ref="tableRef" class="el-table-simple">
				<tbody>
					<tr v-for="(item, index) in tableRules" :key="index">
						<td
							v-for="(col, idx) in item"
							:key="idx"
							:style="getTdStyle(col.colObj)"
							:colspan="col.colSpan"
							:rowspan="col.rowSpan"
						>
							<el-form-item :prop="col.prop" :rules="getRule(col)">
								<!-- 纯文本 -->
								<span :style="getShowStyle(col.colObj)" v-if="col.type === 'text'" class="cell-span">
									<!-- / -->
									<render-content :content="col.value" />
									<el-tooltip v-if="col.tipContent" effect="dark" :content="col.tipContent" raw-content placement="right">
										<el-icon color="#E6A23C"><Opportunity /></el-icon>
									</el-tooltip>
								</span>

								<!-- 下拉框 -->
								<comp-el-select
									v-else-if="col.type === 'select'"
									v-model="formData[col.prop]"
									clearable
									v-bind="getColumnProps(col)"
									style="width: 100%"
									v-on="getColumnEvents(col)"
								/>
								<!-- 级联 -->
								<!-- <comp-dict-cascader
                  v-else-if="col.type === 'dict-cascader'"
                  v-model="formData[col.prop]"
                  clearable
                  v-bind="getColumnProps(col)"
                  v-on="getColumnEvents(col)"
                /> -->
								<!-- 输入框 -->
								<el-input
									v-else-if="col.type === 'input'"
									v-model="formData[col.prop]"
									:clearable="false"
									v-bind="getColumnProps(col)"
									v-on="getColumnEvents(col)"
									@click.stop
								/>
								<!-- 文本域 -->
								<!-- <el-input
                  v-else-if="col.type === 'textarea'"
                  type="textarea"
                  v-model="formData[col.prop]"
                  clearable
                  v-bind="getColumnProps(col)"
                  v-on="getColumnEvents(col)"
                  @click.stop
                /> -->
								<!-- 数字输入框 -->
								<el-input-number
									v-else-if="col.type === 'number-input'"
									v-model="formData[col.prop]"
									:clearable="false"
									v-bind="getColumnProps(col)"
									v-on="getColumnEvents(col)"
									@click.stop
								>
									<template v-if="col.suffix" #append>{{ col.suffix }}</template>
								</el-input-number>
								<!-- 日期组件 -->
								<el-date-picker
									style="width: 100%"
									v-else-if="col.type === 'date'"
									v-model="formData[col.prop]"
									:type="getColumnProps(formData)?.type || 'date'"
									v-bind="getColumnProps(col)"
									v-on="getColumnEvents(col)"
									placeholder="选择日期"
									value-format="YYYY/MM/DD"
								/>
								<el-date-picker
									v-else-if="col.type === 'daterange'"
									v-model="formData[col.prop]"
									:type="getColumnProps(col)?.type || 'daterange'"
									v-bind="getColumnProps(col)"
									v-on="getColumnEvents(col)"
									start-placeholder="开始日期"
									end-placeholder="结束日期"
									range-separator="-"
									value-format="YYYY/MM/DD"
								/>

								<template v-else-if="col.type === 'file'">
									<div v-if="!isEmptyObj(formData[col.prop])" class="table-file-list">
										<span class="file-name">
											<el-tooltip placement="top" :content="formData[col.prop]['fileName']">
												{{ formData[col.prop]["fileName"] }}
											</el-tooltip>
										</span>
										<el-link
											type="primary"
											:underline="false"
											title="查看"
											style="margin-left: 0.05rem"
											@click="handleFilePreviewClick(col)"
											><i class="iconfont icon-preview"></i
										></el-link>
										<el-link type="primary" :underline="false" title="下载" @click.stop="handleFileDownloadClick(col)"
											><i class="iconfont icon-download"></i
										></el-link>
										<el-link
											v-if="!col.props.disabled"
											type="danger"
											:underline="false"
											title="删除"
											@click.stop="handleFileDeleteClick(col)"
											><i class="iconfont icon-dustbin"></i
										></el-link>
									</div>
									<el-link v-if="!col.props.disabled" type="primary" :underline="false" @click="handleUploladClick(col)"
										><i class="iconfont icon-upload" style="font-size: 0.2rem"></i>上传</el-link
									>
								</template>
							</el-form-item>
						</td>
					</tr>
				</tbody>
			</table>
		</el-form>
		<!-- <dialog-upload
      v-if="dialogStatus"
      v-model:dialog-status="dialogStatus"
      :upload-props="{
        limit: 1
      }"
      @dialog-confirm="handleDialogConfirm"
    /> -->
	</div>
</template>
<script lang="ts" setup>
import { h } from "vue";
import { isEmptyObj, isEmpty } from "@/utils/index";
// import { filePreview, fileDownload } from "@utils/file";
import { confirm } from "@/utils/index";
import { cloneDeep } from "lodash-es";
import { Opportunity } from "@element-plus/icons-vue";
// const DialogUpload = defineAsyncComponent(
//   () => import("@components/CompElUpload/DialogUpload.vue")
// );

const props = defineProps({
	canEdit: {
		type: Boolean,
		default: true
	},
	rules: {
		type: Array,
		default: () => []
	},
	data: {
		type: Object,
		default: () => ({})
	}
});

const { proxy } = getCurrentInstance()!;
const formInstance: any = shallowRef(null);
const formData: any = ref({ ...props.data });
const tableRules: any = shallowRef([]);
const dialogStatus = ref(false);
const componentName: any = shallowRef();
const dialogData: any = shallowRef(null);
const action: any = ref("");
watch(
	() => props.rules,
	arr => {
		if (!Array.isArray(arr) || !arr.length) return;
		nextTick(() => {
			initRules();
		});
	},
	{ immediate: true }
);

function initRules() {
	let originRules = cloneDeep(props.rules);
	const exposed: any = proxy?.$.exposed;
	originRules.forEach((item: any) => {
		item.on = {
			change: () => {
				nextTick(() => {
					dispatchEvent(item);
				});
			}
			// blur: () => {
			//   nextTick(() => {
			//     showValidTip(item);
			//   });
			// }
		};
		if (item.type === "file") {
			formData.value[item.prop] = item.value;
		}
		if (Array.isArray(item.validate) && item.validate.length) {
			item.validate.forEach(it => {
				if (it.type === "fn") {
					it.validator = typeof exposed[it.validator] === "function" ? exposed[it.validator] : function () {};
				}
			});
		}
	});
	// const groupRules = originRules.reduce((acc: any, cur: any) => {
	//   if (cur.startRow) {
	//     acc.push([cur]);
	//   } else {
	//     acc[acc.length - 1].push(cur);
	//   }
	//   return acc;
	// }, []);
	const groupByRules = dataArray => {
		return dataArray.reduce((groups, item) => {
			const rowKey = item.colObj.cellRow; // 获取cellRow作为分组键
			if (!groups[rowKey]) {
				groups[rowKey] = [];
			}
			groups[rowKey].push(item);
			return groups;
		}, {});
	};
	const groupRules = groupByRules(originRules);
	tableRules.value = groupRules;
}

function getRule(col) {
	if (Array.isArray(col.validate) && col.validate.length) return col.validate;
	return [];
}

function getColumnProps(column) {
	return typeof column.props === "object" ? column.props : {};
}

function getColumnEvents(column) {
	if (isEmptyObj(column.on)) return {};
	const tempEvt = {};
	Object.keys(column.on).forEach(evtName => {
		tempEvt[evtName] = column.on[evtName];
	});
	return tempEvt;
}

function dispatchEvent(rule) {
	formInstance.value.clearValidate();
}

function excuteFormula(params, prop?) {
	if (isEmpty(params.digit)) return;
	var digit = params.digit ? params.digit : 2;
	const ret: any = caculateExpress(params, prop, "excuteFormula");
	console.log("ret22", ret);
	if (ret === false) return;
	if (isNaN(ret) || ret == Infinity || ret == -Infinity) {
		formData.value[prop] = 0;
	} else {
		formData.value[prop] = ret.toFixed(digit);
	}
}

function caculateExpress(params, prop?, fnStr?) {
	if (isEmpty(params?.express)) return;
	if (isEmpty(params?.fields)) return;
	if (isEmpty(params.resField)) return;
	if (isEmpty(params.digit)) return;
	try {
		var fields = params.fields;
		var resField = params.resField;
		var express = params.express;
		var digit = params.digit ? params.digit : 2;
		const variables = {};
		for (const item of fields) {
			if (fnStr !== "excuteFormula" && isEmpty(formData.value[item])) {
				return false;
			}
			variables[item] = parseFloat(formData.value[item]) || 0;
		}
		const safeExpress = express.replace(/\b([a-zA-Z_]\w*)\b/g, match => `variables.${match}`);
		const calculate = new Function("variables", `return ${safeExpress}`);
		const expressValue = parseFloat(calculate(variables));
		return expressValue;
	} catch (e) {
		proxy?.$showToast("配置错误", "error");
	}
}

function showValidTip(rule) {
	const col = rule.colObj;
	// 必填校验
	if (rule.required && isEmpty(formData.value[rule.prop])) {
		proxy?.$showToast(col.inputTip, "error");
	}
	// 正则校验
	if (rule.checkRule) {
		const inputVal = formData.value[rule.prop];
		if (inputVal) {
			const isPassReg = new RegExp(rule.checkRule.reg).test(inputVal);
			if (!isPassReg) {
				proxy?.$showToast(col.inputTip, "error");
			}
		}
	}
	props.rules.forEach((item: any) => {
		if (Array.isArray(item.emit) && item.emit.length) {
			item.emit.forEach(it => {
				if (it.fnName === "excuteFormula") {
					excuteFormula(it.params, item.prop);
				}
				if (it.fnName === "comppareEqual" && it.params.fields.includes(rule.prop)) {
					comppareEqual(it.params, rule.prop);
				}
				if (it.fnName === "compareUnequal" && it.params.fields.includes(rule.prop)) {
					compareUnequal(it.params, rule.prop);
				}
				if (it.fnName === "compareGreaterThanOrEqual" && it.params.fields.includes(rule.prop)) {
					compareGreaterThanOrEqual(it.params, rule.prop);
				}
				if (it.fnName === "compareLessThanOne" && it.params.fields.includes(rule.prop)) {
					compareLessThanOne(it.params, rule.prop);
				}
			});
		}
	});
}

// 比较相等
function comppareEqual(params, prop) {
	const ret: any = caculateExpress(params, prop, "comppareEqual");
	if (ret === false) return;
	if (isNaN(ret) || ret == Infinity || ret == -Infinity) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	} else if (parseFloat(ret.toFixed(4)) !== 0) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	}
}

// 比较不等
function compareUnequal(params, prop) {
	const ret: any = caculateExpress(params, prop, "compareUnequal");
	if (ret === false) return;
	if (isNaN(ret) || ret == Infinity || ret == -Infinity) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	} else if (parseFloat(ret.toFixed(4)) === 0) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	}
}

// 比较大于或等于
function compareGreaterThanOrEqual(params, prop) {
	const ret: any = caculateExpress(params, prop, "compareGreaterThanOrEqual");
	if (ret === false) return;
	if (isNaN(ret) || ret == Infinity || ret == -Infinity) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	} else if (parseFloat(ret.toFixed(4)) < 0) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	}
}

// 比较是否小于1
function compareLessThanOne(params, prop) {
	const ret: any = caculateExpress(params, prop, "compareLessThanOne");
	if (ret === false) return;
	if (isNaN(ret) || ret == Infinity || ret == -Infinity) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	} else if (Math.abs(parseFloat(ret.toFixed(4))) >= 1) {
		formData.value[prop] = "";
		proxy?.$showToast("公式校验错误", "error");
	}
}

function handleFilePreviewClick(col) {
	if (isEmptyObj(formData.value[col.prop])) return proxy?.$showToast("附件id为空！", "warning");
	filePreview(formData.value[col.prop]["id"]);
}

function handleFileDownloadClick(col) {
	console.log("col", col);
	if (isEmptyObj(formData.value[col.prop])) return proxy?.$showToast("附件id为空！", "warning");
	fileDownload({ fileId: formData.value[col.prop]["id"] });
}

function handleFileDeleteClick(col) {
	confirm(() => {
		formData.value[col.prop] = undefined;
	});
}

let selectedCol: any = null;
function handleUploladClick(col) {
	selectedCol = col;
	dialogStatus.value = true;
}

function handleDialogConfirm({ fileList }) {
	if (!selectedCol || !fileList.length) return;
	formData.value[selectedCol.prop] = {
		fileName: fileList[0].fileName,
		id: fileList[0].fileId
	};
}

function validate() {
	return new Promise(resolve => {
		formInstance.value.validate(valid => {
			if (valid) {
				resolve(cloneDeep(formData.value));
			} else {
				resolve(false);
			}
		});
	});
}

function getFormData() {
	return formData.value;
}

function getShowStyle(colObj) {
	try {
		return colObj.cellStyle ? JSON.parse(colObj.cellStyle) : {};
	} catch {
		return {}; // 解析失败时返回空对象
	}
}

function getTdStyle(colObj) {
	return {
		width: colObj.colWidth || "150px",
		minWidth: colObj.colWidth || "150px",
		maxWidth: colObj.colWidth || "150px",
		height: colObj.rowHeight || "auto",
		minHeight: colObj.rowHeight || "auto",
		maxHeight: colObj.rowHeight || "auto"
	};
}
function hasBrTag(text) {
	// 匹配 <br>、<br/>、<br /> 及其大写变体（不区分大小写）
	return /<br\s*\/?>/i.test(text);
}
function renderContent(props) {
	// 安全处理文本中的<br>标签
	const segments = props.content.split(/(<br\s*\/?>)/gi);
	return h(
		"span",
		segments.map((segment, i) => {
			if (/^<br\s*\/?>$/i.test(segment)) {
				return h("br", { key: `br-${i}` });
			}
			return segment;
		})
	);
}

defineExpose({
	validate,
	excuteFormula,
	comppareEqual,
	compareUnequal,
	compareGreaterThanOrEqual,
	compareLessThanOne,
	getFormData
});
</script>

<style lang="scss" scoped>
table {
	table-layout: auto;
}
.el-table-simple {
	tbody {
		border-top: 1px solid #e3e8ee;
	}

	// td {
	//   padding: 18px;
	// }

	:deep(.el-form-item) {
		margin-bottom: 0;

		.el-form-item__content {
			.cell-span {
				width: 100%;
				padding: 5px 0;
				line-height: 18px;
			}
		}
	}
}
.el-table-simple {
	width: 100%;
	table-layout: fixed;
	border-collapse: collapse;
	color: #606266;
	thead {
		color: #5d6476;
		th {
			font-weight: normal;
			text-align: center;
			border-top: 1px solid #e3e8ee;
			background: #eef1f6;
		}
	}
	tbody {
		font-size: 14px;
		tr {
			transition: background 0.2s;
			&:hover {
				background: #eaf1fb;
			}
		}
	}
	td,
	th {
		padding: 6px 10px;
		line-height: 23px;
		word-break: break-all;
		border-right: 1px solid #e3e8ee;
		border-bottom: 1px solid #e3e8ee;
		&:first-child {
			border-left: 1px solid #e3e8ee;
		}
		.el-icon {
			vertical-align: text-bottom;
		}
	}
}
.line-break {
	white-space: pre-line;
}
</style>
